package com.itc.bpm.framework.factory.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itc.bpm.api.util.validation.ValidationUtils;
import com.itc.bpm.bean.BpmModelTaskCustomVariables;
import com.itc.bpm.dto.BpmModelCreateDto;
import com.itc.bpm.enums.ProcessConstants;
import com.itc.bpm.framework.factory.BpmModelUtil;
import com.itc.bpm.framework.factory.BpmProcessDefinitionService;
import com.itc.bpm.framework.factory.BpmServiceFactory;
import com.itc.bpm.framework.factory.dto.BpmModelMetaInfoRespDTO;
import com.itc.bpm.framework.factory.dto.BpmProcessDefinitionCreateReqDTO;
import com.itc.bpm.framework.factory.vo.BpmModelCreateReqVO;
import com.itc.bpm.framework.factory.vo.BpmModelRespVO;
import com.itc.bpm.framework.factory.vo.BpmModelUpdateReqVO;
import com.itc.bpm.framework.factory.vo.BpmQueryVo;
import com.itc.bpm.service.BpmModelTaskCustomVariablesService;
import com.itc.bpm.util.FlowableUtils;
import com.itc.bpm.util.JsonUtils;
import com.itc.common.core.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BpmModelUtilImpl extends BpmServiceFactory implements BpmModelUtil {
    @Resource
    private RepositoryService repositoryService;

    @Resource
    private BpmProcessDefinitionService processDefinitionService;

    @Transactional(rollbackFor = Exception.class)
    public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) {
        checkKeyNCName(createReqVO.getKey());
        // 校验流程标识已经存在
        Model keyModel = getModelByKey(createReqVO.getKey());
        if (keyModel != null) {
            throw new RuntimeException("流程标识已存在");
        }

        // 创建流程定义
        Model model = repositoryService.newModel();
        model.setKey(createReqVO.getKey());
        model.setName(createReqVO.getName());
        // 保存流程定义
        repositoryService.saveModel(model);
        // 保存 BPMN XML
        saveModelBpmnXml(model, bpmnXml);
        return model.getId();
    }

    private Model getModelByKey(String key) {
        return repositoryService.createModelQuery().modelKey(key).singleResult();
    }

    @Override
    public String createModel(BpmModelCreateDto modelVO, String bpmnXml) {
        return null;
    }

    @Override
    public BpmModelRespVO getModel(String id) {
        Model model = repositoryService.getModel(id);
        if (model == null) {
            return null;
        }
        BpmModelRespVO modelRespVO = new BpmModelRespVO();
        modelRespVO.setId(model.getId());
        modelRespVO.setKey(model.getKey());
        modelRespVO.setName(model.getName());
        BeanUtils.copyProperties(model,modelRespVO);
        modelRespVO.setCreateTime(model.getCreateTime());
        // 拼接 bpmn XML
        byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
        modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
        return modelRespVO;
    }

    @Override
    public BpmModelRespVO getModel2(String key) {
        Model model = repositoryService.createModelQuery().modelKey(key).singleResult();
        if (model == null) {
            return null;
        }
        BpmModelRespVO modelRespVO = new BpmModelRespVO();
        modelRespVO.setId(model.getId());
        modelRespVO.setCreateTime(model.getCreateTime());        // 拼接 bpmn XML
        byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
        modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
        return modelRespVO;
    }


    @Transactional(rollbackFor = Exception.class) // 因为进行多个操作，所以开启事务
    public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) {
        // 校验流程模型存在
        Model model = repositoryService.getModel(updateReqVO.getId());
        if (model == null) {
            throw new RuntimeException("模型不存在");
        }
        model.setName(updateReqVO.getName());
        model.setCategory(updateReqVO.getCategory());
        model.setMetaInfo(buildMetaInfoStr(JsonUtils.jsonToObject(model.getMetaInfo(),BpmModelMetaInfoRespDTO.class),
                updateReqVO.getDescription(), updateReqVO.getFormType(), updateReqVO.getFormId(),
                updateReqVO.getFormCustomCreatePath(), updateReqVO.getFormCustomViewPath()));        // 更新模型

        repositoryService.saveModel(model);
        // 更新 BPMN XML
        saveModelBpmnXml(model, updateReqVO.getBpmnXml());
    }

    String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType,
                            Long formId, String formCustomCreatePath, String formCustomViewPath) {
        if (metaInfo == null) {
            metaInfo = new BpmModelMetaInfoRespDTO();
        }
        // 只有非空，才进行设置，避免更新时的覆盖
        if (StrUtil.isNotEmpty(description)) {
            metaInfo.setDescription(description);
        }
        metaInfo.setFormType(formType);
        metaInfo.setFormId(formId);
        metaInfo.setFormCustomCreatePath(formCustomCreatePath);
        metaInfo.setFormCustomViewPath(formCustomViewPath);
        return JsonUtils.objectToJson(metaInfo);
    }
    @Override
    @Transactional(rollbackFor = Exception.class) // 因为进行多个操作，所以开启事务
    public void deployModel(String id) {
        // 1.1 校验流程模型存在
        Model model = repositoryService.getModel(id);
        if (ObjectUtils.isEmpty(model)) {
            throw new RuntimeException("流程模型不存在");
        }
        // 1.2 校验流程图
        byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
        if (bpmnBytes == null) {
            throw new RuntimeException("流程模型不存在");
        }

        // 1.4 校验任务分配规则已配置
        // taskAssignRuleService.checkTaskAssignRuleAllConfig(id);

        // 1.5 校验模型是否发生修改。如果未修改，则不允许创建
        /*BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes);
        if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
            ProcessDefinition oldProcessDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
            if (oldProcessDefinition != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessDefinition.getId())) {
                throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
            }
        }*/
        BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = new BpmProcessDefinitionCreateReqDTO();

       // BpmModelMetaInfoRespDTO metaInfo = JsonUtils.jsonToObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
        // metaInfo
        //copyTo(metaInfo, definitionCreateReqDTO);
       // BeanUtils.copyProperties(metaInfo,definitionCreateReqDTO);
        definitionCreateReqDTO.setModelId(model.getId());
        definitionCreateReqDTO.setName(model.getName());
        definitionCreateReqDTO.setCategory(model.getCategory());
        definitionCreateReqDTO.setKey(model.getKey());
        definitionCreateReqDTO.setCategory(model.getCategory());
        //definitionCreateReqDTO.setBpmnBytes(model.get);
        // form
        definitionCreateReqDTO.setBpmnBytes(bpmnBytes);

        definitionCreateReqDTO.setKey(model.getKey());
        // 2.1 创建流程定义
        String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);

        // 2.2 将老的流程定义进行挂起。也就是说，只有最新部署的流程定义，才可以发起任务。
        updateProcessDefinitionSuspended(model.getDeploymentId());

        // 2.3 更新 model 的 deploymentId，进行关联
        ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
        model.setDeploymentId(definition.getDeploymentId());
        repositoryService.saveModel(model);
        //记录业务属性值
        saveTaskCustomVarabils(new String(bpmnBytes),definitionId);
    }


    @Autowired
    BpmModelTaskCustomVariablesService bpmModelTaskCustomVariablesService;
    /**
     *  部署xml 讲自定义固定参数存储到数据表
     * @param xml
     */
    public void saveTaskCustomVarabils(String xml,String definitionId){
        Collection<Task> tasks = FlowableUtils.getAllUserTaskEvent(xml);
        bpmModelTaskCustomVariablesService.clearVaribles(definitionId);
        for(Task task:tasks){
            Map<String,Object> valueMap = new HashMap<>();
            Map<String,List<ExtensionAttribute>> atts = task.getAttributes();
            for(String key:atts.keySet()){
                if(CollectionUtils.isNotEmpty(atts.get(key))){
                    String text = atts.get(key).get(0).getValue();
                    valueMap.put(key,text);
                }
            }
            BpmModelTaskCustomVariables variables = new BpmModelTaskCustomVariables();
            variables.setTaskKey(task.getId());
            variables.setProcessDefinitionId(definitionId);
            variables.setVaribalesJson(JsonUtils.mapToJson(valueMap));
            bpmModelTaskCustomVariablesService.save(variables);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteModel(String id) {
        // 校验流程模型存在
        Model model = repositoryService.getModel(id);
        if (model == null) {
            throw new RuntimeException("流程模型不存在");
        }
        // 执行删除
        repositoryService.deleteModel(id);
        // 禁用流程实例
        updateProcessDefinitionSuspended(model.getDeploymentId());
    }

    @Override
    public void updateModelState(String id, Integer state) {
        // 校验流程模型存在
        Model model = repositoryService.getModel(id);
        if (model == null) {
            throw new RuntimeException("流程模型不存在");
        }
        // 校验流程定义存在
        //ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
        /*if (definition == null) {
           // throw exception(PROCESS_DEFINITION_NOT_EXISTS);
        }*/

        // 更新状态
        // processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
    }

    @Override
    public BpmnModel getBpmnModel(String id) {
        byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
        if (ArrayUtil.isEmpty(bpmnBytes)) {
            return null;
        }
        BpmnXMLConverter converter = new BpmnXMLConverter();
        return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
    }

    private void checkKeyNCName(String key) {
        if (!ValidationUtils.isXmlNCName(key)) {
            throw new RuntimeException("流程模型不存在");
        }
    }


    private void saveModelBpmnXml(Model model, String bpmnXml) {
        if (StrUtil.isEmpty(bpmnXml)) {
            return;
        }
        repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
    }

    /**
     * 挂起 deploymentId 对应的流程定义。 这里一个deploymentId 只关联一个流程定义
     * @param deploymentId 流程发布Id.
     */
    private void updateProcessDefinitionSuspended(String deploymentId) {
        if (StrUtil.isEmpty(deploymentId)) {
            return;
        }
        ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId);
        if (oldDefinition == null) {
            return;
        }
        processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
    }

    @Override
    public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) {
        return repositoryService.getBpmnModel(processDefinitionId);
    }



    BpmnModel jsonBpmnModel;
    Process jsonProcess;
    List<SequenceFlow> jsonSequenceFlows;
/*
    @Transactional
    @Override
    public JsonResult updateJsonModel(BpmJsonModelVO modelDO) throws InvocationTargetException, IllegalAccessException {
        //将json 转换为 xml
        BpmJsonModelDO jsonModelDO = new BpmJsonModelDO();
        if(modelDO.getBpmData()!=null){
            //JSONObject object = modelDO.getBpmData();
            jsonProcess = new Process();
            jsonBpmnModel = new BpmnModel();
            jsonSequenceFlows = Lists.newArrayList();
            jsonBpmnModel.addProcess(jsonProcess);
            jsonProcess.setId(modelDO.getBpmKey());
            jsonProcess.setName (modelDO.getName());
            List<JSONObject> flowNode =  modelDO.getBpmData();
            //StartEvent startEvent = createStartEvent(flowNode);
            StartEvent startEvent = createStartEvent2();
            jsonProcess.addFlowElement(startEvent);
            String lastNode = create2(startEvent.getId(), flowNode);
            EndEvent endEvent = createEndEvent();
            jsonProcess.addFlowElement(endEvent);
            jsonProcess.addFlowElement(connect(lastNode, endEvent.getId()));
            new BpmnAutoLayout(jsonBpmnModel).execute();
            String xml = new String(new BpmnXMLConverter().convertToXML(jsonBpmnModel));
            modelDO.setBpmXml(xml);
            jsonModelDO.setBpmData(JsonUtils.objectToJson(modelDO.getBpmData()));

        }
        BeanUtils.copyProperties(modelDO,jsonModelDO);
        String bpmModelId = null;
        if(modelDO.getId()!=null){
            BpmJsonModelDO oldModel = bpmJsonModelMapper.selectById(modelDO.getId());
            bpmModelId = oldModel.getDeployId();
            jsonModelDO.setCreateBy(SecurityUtils.getUsername());
            bpmJsonModelMapper.updateById(jsonModelDO);
        }else {
            BpmModelCreateReqVO createReqVO = new BpmModelCreateReqVO();
            createReqVO.setName(modelDO.getName());
            createReqVO.setKey(modelDO.getBpmKey());
            createReqVO.setDescription(modelDO.getDesription());
            bpmModelId = createModel(createReqVO, jsonModelDO.getBpmXml());
            jsonModelDO.setDeployId(bpmModelId);
            jsonModelDO.setCreateBy(SecurityUtils.getUsername());
            bpmJsonModelMapper.insert(jsonModelDO);
        }
        BpmModelUpdateReqVO updateReqVO = new BpmModelUpdateReqVO();
        updateReqVO.setId(bpmModelId);
        updateReqVO.setBpmnXml(jsonModelDO.getBpmXml());
        updateReqVO.setName(modelDO.getName());
        updateReqVO.setFormType(20);
        updateReqVO.setCategory("oa");
        updateReqVO.setDescription(modelDO.getDesription());
        updateReqVO.setFormCustomViewPath("/bpm");
        updateReqVO.setFormCustomCreatePath("/bpm");
        updateModel(updateReqVO);
        return JsonResult.success();
    }

*/


    String id(String prefix) {
        return prefix + "_" + UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }
    StartEvent createStartEvent(JSONObject flowNode) {
        String nodeType = flowNode.getString("type");
        StartEvent startEvent = new StartEvent();
        startEvent.setId(id("start"));
        if (Type.INITIATOR_TASK.isEqual(nodeType)) {
            JSONObject properties = flowNode.getJSONObject("properties");
            if(StringUtils.isNotEmpty(properties.getString("formKey"))) {
                startEvent.setFormKey(properties.getString("formKey"));
            }
        }
        return startEvent;
    }

    StartEvent createStartEvent2() {
        //String nodeType = flowNode.getString("type");
        StartEvent startEvent = new StartEvent();
        startEvent.setId(id("start"));
       /* if (Type.INITIATOR_TASK.isEqual(nodeType)) {
            JSONObject properties = flowNode.getJSONObject("properties");
            if(StringUtils.isNotEmpty(properties.getString("formKey"))) {
                startEvent.setFormKey(properties.getString("formKey"));
            }
        }*/
        return startEvent;
    }
    enum Type {

        /**
         * 并行事件
         */
        CONCURRENT("concurrent", ParallelGateway.class),

        /**
         * 排他事件
         */
        EXCLUSIVE("exclusive", ExclusiveGateway.class),

        /**
         * 服务任务
         */
        SERVICE_TASK("serviceTask", ServiceTask.class),

        /**
         * 发起人任务
         */
        INITIATOR_TASK("start", ServiceTask.class),

        /**
         * 审批任务
         */
        APPROVER_TASK("approver", ServiceTask.class),

        /**
         * 用户任务
         */
        USER_TASK("userTask", UserTask.class);

        private String type;

        private Class<?> typeClass;

        Type(String type, Class<?> typeClass) {
            this.type = type;
            this.typeClass = typeClass;
        }

        public final static Map<String, Class<?>> TYPE_MAP = Maps.newHashMap();

        static {
            for (Type element : Type.values()) {
                TYPE_MAP.put(element.type, element.typeClass);
            }
        }

        public boolean isEqual(String type) {
            return this.type.equals(type);
        }

    }
    EndEvent createEndEvent() {
        EndEvent endEvent = new EndEvent();
        endEvent.setId(id("end"));
        return endEvent;
    }
    public int getStart(BpmQueryVo pageParam) {
        return (pageParam.getPageNum() - 1) * pageParam.getPageSize();
    }
    String create(String fromId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {
        String nodeType = flowNode.getString("type");

        if (Type.INITIATOR_TASK.isEqual(nodeType)) {
            flowNode.put("incoming", Collections.singletonList(fromId));
            String id = createUserTask(flowNode,nodeType);

            if(flowNode.containsKey("concurrentNodes")) { //并行网关
                return createConcurrentGatewayBuilder(id, flowNode);
            }

            if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                return createExclusiveGatewayBuilder(id, flowNode);
            }

            // 如果当前任务还有后续任务，则遍历创建后续任务
            JSONObject nextNode = flowNode.getJSONObject("childNode");
            if (Objects.nonNull(nextNode)) {
                FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                return create(id, nextNode);
            } else {
                return id;
            }
        } else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {
            flowNode.put("incoming", Collections.singletonList(fromId));
            String id = createUserTask(flowNode,nodeType);
            if(flowNode.containsKey("concurrentNodes")) { //并行网关
                return createConcurrentGatewayBuilder(id, flowNode);
            }

            if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                return createExclusiveGatewayBuilder(id, flowNode);
            }

            // 如果当前任务还有后续任务，则遍历创建后续任务
            JSONObject nextNode = flowNode.getJSONObject("childNode");
            if (Objects.nonNull(nextNode)) {
                FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                return create(id, nextNode);
            } else {
                return id;
            }
        } else if (Type.SERVICE_TASK.isEqual(nodeType)) {
            flowNode.put("incoming", Collections.singletonList(fromId));
            String id = createServiceTask(flowNode);

            if(flowNode.containsKey("concurrentNodes")) { //并行网关
                return createConcurrentGatewayBuilder(id, flowNode);
            }

            if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                return createExclusiveGatewayBuilder(id, flowNode);
            }

            // 如果当前任务还有后续任务，则遍历创建后续任务
            JSONObject nextNode = flowNode.getJSONObject("childNode");
            if (Objects.nonNull(nextNode)) {
                FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                return create(id, nextNode);
            } else {
                return id;
            }
        }
        else {
            throw new RuntimeException("未知节点类型: nodeType=" + nodeType);
        }
    }


    String create2(String fromId, List<JSONObject> flowNodes) throws InvocationTargetException, IllegalAccessException {
        String lastId = fromId;
        for(JSONObject flowNode:flowNodes){
            fromId = lastId;
            String nodeType = flowNode.getString("type");
            if (Type.INITIATOR_TASK.isEqual(nodeType)) {
                flowNode.put("incoming", Collections.singletonList(fromId));
                String id = createUserTask(flowNode,nodeType);

                if(flowNode.containsKey("concurrentNodes")) { //并行网关
                    lastId = createConcurrentGatewayBuilder(id, flowNode);
                }

                if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                    lastId = createExclusiveGatewayBuilder(id, flowNode);
                }

                // 如果当前任务还有后续任务，则遍历创建后续任务
                JSONObject nextNode = flowNode.getJSONObject("childNode");
                if (Objects.nonNull(nextNode)) {
                    FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                    lastId = create(id, nextNode);
                } else {
                    lastId = id;
                }
            } else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {
                flowNode.put("incoming", Collections.singletonList(fromId));
                String id = createUserTask2(flowNode,nodeType);
                if(flowNode.containsKey("concurrentNodes")) { //并行网关
                    return createConcurrentGatewayBuilder(id, flowNode);
                }

                if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                    return createExclusiveGatewayBuilder(id, flowNode);
                }

                // 如果当前任务还有后续任务，则遍历创建后续任务
                JSONObject nextNode = flowNode.getJSONObject("childNode");
                if (Objects.nonNull(nextNode)) {
                    FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                    return create(id, nextNode);
                }
                lastId = id;
            } else if (Type.SERVICE_TASK.isEqual(nodeType)) {
                flowNode.put("incoming", Collections.singletonList(fromId));
                String id = createServiceTask(flowNode);

                if(flowNode.containsKey("concurrentNodes")) { //并行网关
                    return createConcurrentGatewayBuilder(id, flowNode);
                }

                if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关
                    return createExclusiveGatewayBuilder(id, flowNode);
                }

                // 如果当前任务还有后续任务，则遍历创建后续任务
                JSONObject nextNode = flowNode.getJSONObject("childNode");
                if (Objects.nonNull(nextNode)) {
                    FlowElement flowElement = jsonBpmnModel.getFlowElement(id);
                    return create(id, nextNode);
                } else {
                    return id;
                }
            }
            else {
                throw new RuntimeException("未知节点类型: nodeType=" + nodeType);
            }
        }
        return lastId;
    }


    String createExclusiveGatewayBuilder(String formId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {
        //String name = flowNode.getString("nodeName");
        String exclusiveGatewayId = id("exclusiveGateway");
        ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
        exclusiveGateway.setId(exclusiveGatewayId);
        exclusiveGateway.setName("排它条件网关");
        jsonProcess.addFlowElement(exclusiveGateway);
        jsonProcess.addFlowElement(connect(formId, exclusiveGatewayId));

        if (Objects.isNull(flowNode.getJSONArray("conditionNodes")) && Objects.isNull(flowNode.getJSONObject("childNode"))) {
            return exclusiveGatewayId;
        }
        List<JSONObject> flowNodes = Optional.ofNullable(flowNode.getJSONArray("conditionNodes")).map(e -> e.toJavaList(JSONObject.class)).orElse(Collections.emptyList());
        List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());

        List<JSONObject> conditions = Lists.newCopyOnWriteArrayList();
        for (JSONObject element : flowNodes) {
            JSONObject childNode = element.getJSONObject("childNode");
            JSONObject properties = element.getJSONObject("properties");
            String nodeName = properties.getString("title");
            String expression = properties.getString("conditions");

            if (Objects.isNull(childNode)) {
                incoming.add(exclusiveGatewayId);
                JSONObject condition = new JSONObject();
                condition.fluentPut("nodeName", nodeName)
                        .fluentPut("expression", expression);
                conditions.add(condition);
                continue;
            }
            // 只生成一个任务，同时设置当前任务的条件
            childNode.put("incoming", Collections.singletonList(exclusiveGatewayId));
            String identifier = create(exclusiveGatewayId, childNode);
            List<SequenceFlow> flows = jsonSequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId, flow.getSourceRef()))
                    .collect(Collectors.toList());

            flows.stream().forEach(
                    e -> {
                        if (StringUtils.isBlank(e.getName()) && StringUtils.isNotBlank(nodeName)) {
                            e.setName(nodeName);
                        }
                        // 设置条件表达式
                        if (Objects.isNull(e.getConditionExpression()) && StringUtils.isNotBlank(expression)) {
                            e.setConditionExpression(expression);
                        }
                    }
            );
            if (Objects.nonNull(identifier)) {
                incoming.add(identifier);
            }
        }


        JSONObject childNode = flowNode.getJSONObject("childNode");
        if (Objects.nonNull(childNode)) {
            if (incoming == null || incoming.isEmpty()) {
                return create(exclusiveGatewayId, childNode);
            } else {
                // 所有 service task 连接 end exclusive gateway
                childNode.put("incoming", incoming);
                FlowElement flowElement = jsonBpmnModel.getFlowElement(incoming.get(0));
                // 1.0 先进行边连接, 暂存 nextNode
                JSONObject nextNode = childNode.getJSONObject("childNode");
                childNode.put("childNode", null);
                String identifier = create(flowElement.getId(), childNode);
                for (int i = 1; i < incoming.size(); i++) {
                    jsonProcess.addFlowElement(connect(incoming.get(i), identifier));
                }

                //  针对 gateway 空任务分支 添加条件表达式
                if (!conditions.isEmpty()) {
                    FlowElement flowElement1 = jsonBpmnModel.getFlowElement(identifier);
                    // 获取从 gateway 到目标节点 未设置条件表达式的节点
                    List<SequenceFlow> flows = jsonSequenceFlows.stream().filter(flow -> StringUtils.equals(flowElement1.getId(), flow.getTargetRef()))
                            .filter(flow -> StringUtils.equals(flow.getSourceRef(), exclusiveGatewayId))
                            .collect(Collectors.toList());
                    flows.stream().forEach(sequenceFlow -> {
                        if (!conditions.isEmpty()) {
                            JSONObject condition = conditions.get(0);
                            String nodeName = condition.getString("content");
                            String expression = condition.getString("expression");

                            if (StringUtils.isBlank(sequenceFlow.getName()) && StringUtils.isNotBlank(nodeName)) {
                                sequenceFlow.setName(nodeName);
                            }
                            // 设置条件表达式
                            if (Objects.isNull(sequenceFlow.getConditionExpression()) && StringUtils.isNotBlank(expression)) {
                                sequenceFlow.setConditionExpression(expression);
                            }

                            conditions.remove(0);
                        }
                    });

                }

                // 1.1 边连接完成后，在进行 nextNode 创建
                if (Objects.nonNull(nextNode)) {
                    return create(identifier, nextNode);
                } else {
                    return identifier;
                }
            }
        }
        return exclusiveGatewayId;
    }

    String createConcurrentGatewayBuilder(String fromId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {
        //String name = flowNode.getString("nodeName");
        //下面创建并行网关并进行连线
        ParallelGateway parallelGateway = new ParallelGateway();
        String parallelGatewayId = id("parallelGateway");
        parallelGateway.setId(parallelGatewayId);
        parallelGateway.setName("并行网关");
        jsonProcess.addFlowElement(parallelGateway);
        jsonProcess.addFlowElement(connect(fromId, parallelGatewayId));

        if (Objects.isNull(flowNode.getJSONArray("concurrentNodes"))
                && Objects.isNull(flowNode.getJSONObject("childNode"))) {
            return parallelGatewayId;
        }

        //获取并行列表数据
        List<JSONObject> flowNodes = Optional.ofNullable(flowNode.getJSONArray("concurrentNodes")).map(e -> e.toJavaList(JSONObject.class)).orElse(Collections.emptyList());
        List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());
        for (JSONObject element : flowNodes) {
            JSONObject childNode = element.getJSONObject("childNode");
            if (Objects.isNull(childNode)) {//没子节点,就把并行id加入入口队列
                incoming.add(parallelGatewayId);
                continue;
            }
            String identifier = create(parallelGatewayId, childNode);
            if (Objects.nonNull(identifier)) {//否则加入有子节点的用户id
                incoming.add(identifier);
            }
        }

        JSONObject childNode = flowNode.getJSONObject("childNode");

        if (Objects.nonNull(childNode)) {
            // 普通结束网关
            if (CollectionUtils.isEmpty(incoming)) {
                return create(parallelGatewayId, childNode);
            } else {
                // 所有 user task 连接 end parallel gateway
                childNode.put("incoming", incoming);
                FlowElement flowElement = jsonBpmnModel.getFlowElement(incoming.get(0));
                // 1.0 先进行边连接, 暂存 nextNode
                JSONObject nextNode = childNode.getJSONObject("childNode");
                childNode.put("childNode", null); //不加这个,下面创建子节点会进入递归了
                String identifier = create(incoming.get(0), childNode);
                for (int i = 1; i < incoming.size(); i++) {//其中0之前创建的时候已经连接过了，所以从1开始补另外一条
                    FlowElement flowElementIncoming = jsonBpmnModel.getFlowElement(incoming.get(i));
                    jsonProcess.addFlowElement(connect(flowElementIncoming.getId(), identifier));
                }
                // 1.1 边连接完成后，在进行 nextNode 创建
                if (Objects.nonNull(nextNode)) {
                    return create(identifier, nextNode);
                } else {
                    return identifier;
                }
            }
        }
        if(incoming.size()>0) {
            return incoming.get(1);
        }
        else {
            return parallelGatewayId;
        }

    }

    String createUserTask(JSONObject flowNode, String nodeType) {
        List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);
        // 自动生成id
        String id = id("userTask");
        if (incoming != null && !incoming.isEmpty()) {
            UserTask userTask = new UserTask();
            JSONObject properties = flowNode.getJSONObject("properties");
            userTask.setName(properties.getString("title"));
            userTask.setId(id);
            List<ExtensionAttribute> attributes = new  ArrayList<ExtensionAttribute>();
            if (Type.INITIATOR_TASK.isEqual(nodeType)) {
                ExtensionAttribute extAttribute =  new ExtensionAttribute();
                extAttribute.setNamespace(ProcessConstants.NAMASPASE);
                extAttribute.setName("dataType");
                extAttribute.setValue("INITIATOR");
                attributes.add(extAttribute);
                userTask.addAttribute(extAttribute);
                userTask.setAssignee("${initiator}");
            } else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {
                String assignType = properties.getString("assigneeType");
                if(StringUtils.equalsAnyIgnoreCase("user", assignType)) {
                    JSONArray approvers = properties.getJSONArray("approvers");
                    JSONObject approver = approvers.getJSONObject(0);
                    ExtensionAttribute extDataTypeAttribute =  new ExtensionAttribute();
                    extDataTypeAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extDataTypeAttribute.setName("dataType");
                    extDataTypeAttribute.setValue("USERS");
                    userTask.addAttribute(extDataTypeAttribute);
                    ExtensionAttribute extTextAttribute =  new ExtensionAttribute();
                    extTextAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extTextAttribute.setName("text");
                    extTextAttribute.setValue(approver.getString("nickName"));
                    userTask.addAttribute(extTextAttribute);
                    userTask.setFormKey(properties.getString("formKey"));
                    userTask.setAssignee(approver.getString("userName"));
                    //userTask.setCandidateUsers();
                }
                else if (StringUtils.equalsAnyIgnoreCase("director", assignType)) {
                    ExtensionAttribute extDataTypeAttribute =  new ExtensionAttribute();
                    extDataTypeAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extDataTypeAttribute.setName("dataType");
                    extDataTypeAttribute.setValue("MANAGER");
                    userTask.addAttribute(extDataTypeAttribute);
                    ExtensionAttribute extTextAttribute =  new ExtensionAttribute();
                    extTextAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extTextAttribute.setName("text");
                    extTextAttribute.setValue("部门经理");
                    userTask.addAttribute(extTextAttribute);
                    userTask.setFormKey(properties.getString("formKey"));
                    userTask.setAssignee("${DepManagerHandler.getUser(execution)}");
                }
                else if (StringUtils.equalsAnyIgnoreCase("role", assignType)) {
                    JSONArray approvers = properties.getJSONArray("approvers");
                    JSONObject approver = approvers.getJSONObject(0);
                    ExtensionAttribute extDataTypeAttribute =  new ExtensionAttribute();
                    extDataTypeAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extDataTypeAttribute.setName("dataType");
                    extDataTypeAttribute.setValue("ROLES");
                    userTask.addAttribute(extDataTypeAttribute);
                    ExtensionAttribute extTextAttribute =  new ExtensionAttribute();
                    extTextAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extTextAttribute.setName("text");
                    extTextAttribute.setValue(approver.getString("roleName"));
                    userTask.addAttribute(extTextAttribute);
                    userTask.setFormKey(properties.getString("formKey"));
                   /* List<SysRole> sysroleslist = approvers.toJavaList(SysRole.class);
                    List<String> roleslist = sysroleslist.stream().map(e->e.getRoleKey()).collect(Collectors.toList());
                    userTask.setCandidateGroups(roleslist);
                    userTask.setAssignee("${assignee}");
                    MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();
                    if(StringUtils.equalsAnyIgnoreCase(properties.getString("counterSign"), "true")) {//并行会签
                        loopCharacteristics.setSequential(false);
                        loopCharacteristics.setInputDataItem("${multiInstanceHandler.getUserNames(execution)}");
                        loopCharacteristics.setElementVariable("assignee");
                        loopCharacteristics.setCompletionCondition("${nrOfCompletedInstances &gt;= nrOfInstances}");
                    }
                    else {
                        loopCharacteristics.setSequential(false);
                        loopCharacteristics.setInputDataItem("${multiInstanceHandler.getUserNames(execution)}");
                        loopCharacteristics.setElementVariable("assignee");
                        loopCharacteristics.setCompletionCondition("${nrOfCompletedInstances &gt; 0}");
                    }*/
                    //userTask.setLoopCharacteristics(loopCharacteristics);
                }
            }

            jsonProcess.addFlowElement(userTask);
            jsonProcess.addFlowElement(connect(incoming.get(0), id));
        }
        return id;
    }
    String createUserTask2(JSONObject flowNode, String nodeType) {
        List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);
        // 自动生成id
        String id = id("userTask");
        if (incoming != null && !incoming.isEmpty()) {
            UserTask userTask = new UserTask();
            //JSONObject properties = flowNode.getJSONObject("properties");
            userTask.setName(flowNode.getString("title"));
            userTask.setId(id);
            List<ExtensionAttribute> attributes = new  ArrayList<ExtensionAttribute>();
            if (Type.INITIATOR_TASK.isEqual(nodeType)) {
                ExtensionAttribute extAttribute =  new ExtensionAttribute();
                extAttribute.setNamespace(ProcessConstants.NAMASPASE);
                extAttribute.setName("dataType");
                extAttribute.setValue("INITIATOR");
                attributes.add(extAttribute);
                userTask.addAttribute(extAttribute);
                userTask.setAssignee("${initiator}");
            } else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {
                String assignType = flowNode.getString("assigneeType");
                if(StringUtils.equalsAnyIgnoreCase("user", assignType)) {
                    JSONArray approvers = flowNode.getJSONArray("approvers");
                    List<String> users = new ArrayList<>();
                    for(int i=0;i<approvers.size();i++){
                        JSONObject item = approvers.getJSONObject(i);
                        users.add(item.getString("userName"));
                    }
                    JSONObject approver = approvers.getJSONObject(0);
                    ExtensionAttribute extDataTypeAttribute =  new ExtensionAttribute();
                    extDataTypeAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extDataTypeAttribute.setName("dataType");
                    extDataTypeAttribute.setValue("USERS");
                    userTask.addAttribute(extDataTypeAttribute);
                    ExtensionAttribute extTextAttribute =  new ExtensionAttribute();
                    extTextAttribute.setNamespace(ProcessConstants.NAMASPASE);
                    extTextAttribute.setName("text");
                    extTextAttribute.setValue(approver.getString("nickName"));
                    userTask.addAttribute(extTextAttribute);
                    userTask.setFormKey(flowNode.getString("formKey"));
                    userTask.setCandidateUsers(users);
                    //userTask.setAssignee(approver.getString("userName"));
                }
            }
            jsonProcess.addFlowElement(userTask);
            jsonProcess.addFlowElement(connect(incoming.get(0), id));
        }
        return id;
    }

    SequenceFlow connect(String from, String to) {
        SequenceFlow flow = new SequenceFlow();
        flow.setId(id("sequenceFlow"));
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        jsonSequenceFlows.add(flow);
        return flow;
    }
    String createServiceTask(JSONObject flowNode) {
        List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);
        // 自动生成id
        String id = id("serviceTask");
        if (incoming != null && !incoming.isEmpty()) {
            ServiceTask serviceTask = new ServiceTask();
            serviceTask.setName(flowNode.getString("nodeName"));
            serviceTask.setId(id);
            jsonProcess.addFlowElement(serviceTask);
            jsonProcess.addFlowElement(connect(incoming.get(0), id));
        }
        return id;
    }
}
